/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"TextureHost.h"#include"CompositableHost.h" // for CompositableHost#include"LayerScope.h"#include"LayersLogging.h" // for AppendToString#include"mozilla/gfx/2D.h" // for DataSourceSurface, Factory#include"mozilla/gfx/gfxVars.h"#include"mozilla/ipc/Shmem.h" // for Shmem#include"mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager#include"mozilla/layers/CompositorBridgeParent.h"#include"mozilla/layers/Compositor.h" // for Compositor#include"mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator#include"mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc#include"mozilla/layers/TextureHostBasic.h"#include"mozilla/layers/TextureHostOGL.h" // for TextureHostOGL#include"mozilla/layers/ImageDataSerializer.h"#include"mozilla/layers/TextureClient.h"#include"mozilla/layers/GPUVideoTextureHost.h"#include"mozilla/layers/WebRenderTextureHost.h"#include"mozilla/webrender/RenderBufferTextureHost.h"#include"mozilla/webrender/RenderThread.h"#include"mozilla/webrender/WebRenderAPI.h"#include"nsAString.h"#include"mozilla/RefPtr.h" // for nsRefPtr#include"nsPrintfCString.h" // for nsPrintfCString#include"mozilla/layers/PTextureParent.h"#include"mozilla/Unused.h"#include<limits>#include"../opengl/CompositorOGL.h"#include"gfxPrefs.h"#include"gfxUtils.h"#include"IPDLActor.h"#ifdef MOZ_ENABLE_D3D10_LAYER#include"../d3d11/CompositorD3D11.h"#endif#ifdef MOZ_X11#include"mozilla/layers/X11TextureHost.h"#endif#ifdef XP_MACOSX#include"../opengl/MacIOSurfaceTextureHostOGL.h"#endif#ifdef XP_WIN#include"mozilla/layers/TextureDIB.h"#endif#if 0#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)#else#define RECYCLE_LOG(...) do { } while (0)#endifnamespacemozilla{namespacelayers{/** * TextureParent is the host-side IPDL glue between TextureClient and TextureHost. * It is an IPDL actor just like LayerParent, CompositableParent, etc. */classTextureParent:publicParentActor<PTextureParent>{public:explicitTextureParent(HostIPCAllocator*aAllocator,uint64_taSerial,constwr::MaybeExternalImageId&aExternalImageId);~TextureParent();boolInit(constSurfaceDescriptor&aSharedData,constLayersBackend&aLayersBackend,constTextureFlags&aFlags);voidNotifyNotUsed(uint64_taTransactionId);virtualmozilla::ipc::IPCResultRecvRecycleTexture(constTextureFlags&aTextureFlags)override;TextureHost*GetTextureHost(){returnmTextureHost;}virtualvoidDestroy()override;uint64_tGetSerial()const{returnmSerial;}HostIPCAllocator*mSurfaceAllocator;RefPtr<TextureHost>mTextureHost;// mSerial is unique in TextureClient's process.constuint64_tmSerial;wr::MaybeExternalImageIdmExternalImageId;};staticboolWrapWithWebRenderTextureHost(ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags){if(!gfxVars::UseWebRender()||(aFlags&TextureFlags::SNAPSHOT)||(aBackend!=LayersBackend::LAYERS_WR)||(!aDeallocator->UsesImageBridge()&&!aDeallocator->AsCompositorBridgeParentBase())){returnfalse;}returntrue;}////////////////////////////////////////////////////////////////////////////////PTextureParent*TextureHost::CreateIPDLActor(HostIPCAllocator*aAllocator,constSurfaceDescriptor&aSharedData,LayersBackendaLayersBackend,TextureFlagsaFlags,uint64_taSerial,constwr::MaybeExternalImageId&aExternalImageId){if(aSharedData.type()==SurfaceDescriptor::TSurfaceDescriptorBuffer&&aSharedData.get_SurfaceDescriptorBuffer().data().type()==MemoryOrShmem::Tuintptr_t&&!aAllocator->IsSameProcess()){NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");returnnullptr;}TextureParent*actor=newTextureParent(aAllocator,aSerial,aExternalImageId);if(!actor->Init(aSharedData,aLayersBackend,aFlags)){deleteactor;returnnullptr;}returnactor;}// staticboolTextureHost::DestroyIPDLActor(PTextureParent*actor){deleteactor;returntrue;}// staticboolTextureHost::SendDeleteIPDLActor(PTextureParent*actor){returnPTextureParent::Send__delete__(actor);}// staticTextureHost*TextureHost::AsTextureHost(PTextureParent*actor){if(!actor){returnnullptr;}returnstatic_cast<TextureParent*>(actor)->mTextureHost;}// staticuint64_tTextureHost::GetTextureSerial(PTextureParent*actor){if(!actor){returnUINT64_MAX;}returnstatic_cast<TextureParent*>(actor)->mSerial;}PTextureParent*TextureHost::GetIPDLActor(){returnmActor;}voidTextureHost::SetLastFwdTransactionId(uint64_taTransactionId){MOZ_ASSERT(mFwdTransactionId<=aTransactionId);mFwdTransactionId=aTransactionId;}// implemented in TextureHostOGL.cppalready_AddRefed<TextureHost>CreateTextureHostOGL(constSurfaceDescriptor&aDesc,ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags);// implemented in TextureHostBasic.cppalready_AddRefed<TextureHost>CreateTextureHostBasic(constSurfaceDescriptor&aDesc,ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags);// implemented in TextureD3D11.cppalready_AddRefed<TextureHost>CreateTextureHostD3D11(constSurfaceDescriptor&aDesc,ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags);already_AddRefed<TextureHost>TextureHost::Create(constSurfaceDescriptor&aDesc,ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags,wr::MaybeExternalImageId&aExternalImageId){RefPtr<TextureHost>result;switch(aDesc.type()){caseSurfaceDescriptor::TSurfaceDescriptorBuffer:caseSurfaceDescriptor::TSurfaceDescriptorDIB:caseSurfaceDescriptor::TSurfaceDescriptorFileMapping:caseSurfaceDescriptor::TSurfaceDescriptorGPUVideo:result=CreateBackendIndependentTextureHost(aDesc,aDeallocator,aBackend,aFlags);break;caseSurfaceDescriptor::TEGLImageDescriptor:caseSurfaceDescriptor::TSurfaceTextureDescriptor:caseSurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:result=CreateTextureHostOGL(aDesc,aDeallocator,aBackend,aFlags);break;caseSurfaceDescriptor::TSurfaceDescriptorMacIOSurface:if(aBackend==LayersBackend::LAYERS_OPENGL||aBackend==LayersBackend::LAYERS_WR){result=CreateTextureHostOGL(aDesc,aDeallocator,aBackend,aFlags);break;}else{result=CreateTextureHostBasic(aDesc,aDeallocator,aBackend,aFlags);break;}#ifdef MOZ_X11caseSurfaceDescriptor::TSurfaceDescriptorX11:{constSurfaceDescriptorX11&desc=aDesc.get_SurfaceDescriptorX11();result=MakeAndAddRef<X11TextureHost>(aFlags,desc);break;}#endif#ifdef XP_WINcaseSurfaceDescriptor::TSurfaceDescriptorD3D10:caseSurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:result=CreateTextureHostD3D11(aDesc,aDeallocator,aBackend,aFlags);break;#endifdefault:MOZ_CRASH("GFX: Unsupported Surface type host");}if(WrapWithWebRenderTextureHost(aDeallocator,aBackend,aFlags)){MOZ_ASSERT(aExternalImageId.isSome());result=newWebRenderTextureHost(aDesc,aFlags,result,aExternalImageId.ref());}returnresult.forget();}already_AddRefed<TextureHost>CreateBackendIndependentTextureHost(constSurfaceDescriptor&aDesc,ISurfaceAllocator*aDeallocator,LayersBackendaBackend,TextureFlagsaFlags){RefPtr<TextureHost>result;switch(aDesc.type()){caseSurfaceDescriptor::TSurfaceDescriptorBuffer:{constSurfaceDescriptorBuffer&bufferDesc=aDesc.get_SurfaceDescriptorBuffer();constMemoryOrShmem&data=bufferDesc.data();switch(data.type()){caseMemoryOrShmem::TShmem:{result=newShmemTextureHost(data.get_Shmem(),bufferDesc.desc(),aDeallocator,aFlags);break;}caseMemoryOrShmem::Tuintptr_t:{result=newMemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),bufferDesc.desc(),aFlags);break;}default:gfxCriticalError()<<"Failed texture host for backend "<<(int)data.type();MOZ_CRASH("GFX: No texture host for backend");}break;}caseSurfaceDescriptor::TSurfaceDescriptorGPUVideo:{result=newGPUVideoTextureHost(aFlags,aDesc.get_SurfaceDescriptorGPUVideo());break;}#ifdef XP_WINcaseSurfaceDescriptor::TSurfaceDescriptorDIB:{result=newDIBTextureHost(aFlags,aDesc);break;}caseSurfaceDescriptor::TSurfaceDescriptorFileMapping:{result=newTextureHostFileMapping(aFlags,aDesc);break;}#endifdefault:{NS_WARNING("No backend independent TextureHost for this descriptor type");}}returnresult.forget();}TextureHost::TextureHost(TextureFlagsaFlags):AtomicRefCountedWithFinalize("TextureHost"),mActor(nullptr),mFlags(aFlags),mCompositableCount(0),mFwdTransactionId(0){}TextureHost::~TextureHost(){// If we still have a ReadLock, unlock it. At this point we don't care about// the texture client being written into on the other side since it should be// destroyed by now. But we will hit assertions if we don't ReadUnlock before// destroying the lock itself.ReadUnlock();}voidTextureHost::Finalize(){if(!(GetFlags()&TextureFlags::DEALLOCATE_CLIENT)){DeallocateSharedData();DeallocateDeviceData();}}voidTextureHost::UnbindTextureSource(){if(mReadLock){// This TextureHost is not used anymore. Since most compositor backends are// working asynchronously under the hood a compositor could still be using// this texture, so it is generally best to wait until the end of the next// composition before calling ReadUnlock. We ask the compositor to take care// of that for us.if(mProvider){mProvider->UnlockAfterComposition(this);}else{// GetCompositor returned null which means no compositor can be using this// texture. We can ReadUnlock right away.ReadUnlock();}}}voidTextureHost::RecycleTexture(TextureFlagsaFlags){MOZ_ASSERT(GetFlags()&TextureFlags::RECYCLE);MOZ_ASSERT(aFlags&TextureFlags::RECYCLE);mFlags=aFlags;}voidTextureHost::NotifyNotUsed(){if(!mActor){return;}// Do not need to call NotifyNotUsed() if TextureHost does not have// TextureFlags::RECYCLE flag.if(!(GetFlags()&TextureFlags::RECYCLE)){return;}// The following cases do not need to defer NotifyNotUsed until next Composite.// - TextureHost does not have Compositor.// - Compositor is BasicCompositor.// - TextureHost has intermediate buffer.// end of buffer usage.if(!mProvider||HasIntermediateBuffer()||!mProvider->NotifyNotUsedAfterComposition(this)){static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);return;}}voidTextureHost::CallNotifyNotUsed(){if(!mActor){return;}static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);}voidTextureHost::PrintInfo(std::stringstream&aStream,constchar*aPrefix){aStream<<aPrefix;aStream<<nsPrintfCString("%s (0x%p)",Name(),this).get();// Note: the TextureHost needs to be locked before it is safe to call// GetSize() and GetFormat() on it.if(Lock()){AppendToString(aStream,GetSize()," [size=","]");AppendToString(aStream,GetFormat()," [format=","]");Unlock();}AppendToString(aStream,mFlags," [flags=","]");#ifdef MOZ_DUMP_PAINTINGif(gfxPrefs::LayersDumpTexture()||profiler_feature_active(ProfilerFeature::LayersDump)){nsAutoCStringpfx(aPrefix);pfx+=" ";aStream<<"\n"<<pfx.get()<<"Surface: ";RefPtr<gfx::DataSourceSurface>dSurf=GetAsSurface();if(dSurf){aStream<<gfxUtils::GetAsLZ4Base64Str(dSurf).get();}}#endif}voidTextureHost::Updated(constnsIntRegion*aRegion){LayerScope::ContentChanged(this);UpdatedInternal(aRegion);}TextureSource::TextureSource():mCompositableCount(0){}TextureSource::~TextureSource(){}constchar*TextureSource::Name()const{MOZ_CRASH("GFX: TextureSource without class name");return"TextureSource";}BufferTextureHost::BufferTextureHost(constBufferDescriptor&aDesc,TextureFlagsaFlags):TextureHost(aFlags),mUpdateSerial(1),mLocked(false),mNeedsFullUpdate(false){mDescriptor=aDesc;switch(mDescriptor.type()){caseBufferDescriptor::TYCbCrDescriptor:{constYCbCrDescriptor&ycbcr=mDescriptor.get_YCbCrDescriptor();mSize=ycbcr.ySize();mFormat=gfx::SurfaceFormat::YUV;mHasIntermediateBuffer=ycbcr.hasIntermediateBuffer();break;}caseBufferDescriptor::TRGBDescriptor:{constRGBDescriptor&rgb=mDescriptor.get_RGBDescriptor();mSize=rgb.size();mFormat=rgb.format();mHasIntermediateBuffer=rgb.hasIntermediateBuffer();break;}default:gfxCriticalError()<<"Bad buffer host descriptor "<<(int)mDescriptor.type();MOZ_CRASH("GFX: Bad descriptor");}if(aFlags&TextureFlags::COMPONENT_ALPHA){// One texture of a component alpha texture pair will start out all white.// This hack allows us to easily make sure that white will be uploaded.// See bug 1138934mNeedsFullUpdate=true;}}BufferTextureHost::~BufferTextureHost(){}voidBufferTextureHost::UpdatedInternal(constnsIntRegion*aRegion){++mUpdateSerial;// If the last frame wasn't uploaded yet, and we -don't- have a partial update,// we still need to update the full surface.if(aRegion&&!mNeedsFullUpdate){mMaybeUpdatedRegion.OrWith(*aRegion);}else{mNeedsFullUpdate=true;}if(GetFlags()&TextureFlags::IMMEDIATE_UPLOAD){DebugOnly<bool>result=MaybeUpload(!mNeedsFullUpdate?&mMaybeUpdatedRegion:nullptr);NS_WARNING_ASSERTION(result,"Failed to upload a texture");}}voidBufferTextureHost::SetTextureSourceProvider(TextureSourceProvider*aProvider){if(mProvider==aProvider){return;}if(mFirstSource&&mFirstSource->IsOwnedBy(this)){mFirstSource->SetOwner(nullptr);}if(mFirstSource){mFirstSource=nullptr;mNeedsFullUpdate=true;}mProvider=aProvider;}voidBufferTextureHost::DeallocateDeviceData(){if(mFirstSource&&mFirstSource->NumCompositableRefs()>0){return;}if(!mFirstSource||!mFirstSource->IsOwnedBy(this)){mFirstSource=nullptr;return;}mFirstSource->SetOwner(nullptr);RefPtr<TextureSource>it=mFirstSource;while(it){it->DeallocateDeviceData();it=it->GetNextSibling();}}boolBufferTextureHost::Lock(){MOZ_ASSERT(!mLocked);if(!UploadIfNeeded()){returnfalse;}mLocked=!!mFirstSource;returnmLocked;}voidBufferTextureHost::Unlock(){MOZ_ASSERT(mLocked);mLocked=false;}voidBufferTextureHost::CreateRenderTexture(constwr::ExternalImageId&aExternalImageId){RefPtr<wr::RenderTextureHost>texture=newwr::RenderBufferTextureHost(GetBuffer(),GetBufferDescriptor());wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),texture.forget());}voidBufferTextureHost::GetWRImageKeys(nsTArray<wr::ImageKey>&aImageKeys,conststd::function<wr::ImageKey()>&aImageKeyAllocator){MOZ_ASSERT(aImageKeys.IsEmpty());if(GetFormat()!=gfx::SurfaceFormat::YUV){// 1 image keyaImageKeys.AppendElement(aImageKeyAllocator());MOZ_ASSERT(aImageKeys.Length()==1);}else{// 3 image keyaImageKeys.AppendElement(aImageKeyAllocator());aImageKeys.AppendElement(aImageKeyAllocator());aImageKeys.AppendElement(aImageKeyAllocator());MOZ_ASSERT(aImageKeys.Length()==3);}}voidBufferTextureHost::AddWRImage(wr::WebRenderAPI*aAPI,Range<constwr::ImageKey>&aImageKeys,constwr::ExternalImageId&aExtID){if(GetFormat()!=gfx::SurfaceFormat::YUV){MOZ_ASSERT(aImageKeys.length()==1);wr::ImageDescriptordescriptor(GetSize(),ImageDataSerializer::ComputeRGBStride(GetFormat(),GetSize().width),GetFormat());aAPI->AddExternalImageBuffer(aImageKeys[0],descriptor,aExtID);}else{MOZ_ASSERT(aImageKeys.length()==3);constlayers::YCbCrDescriptor&desc=mDescriptor.get_YCbCrDescriptor();wr::ImageDescriptoryDescriptor(desc.ySize(),desc.ySize().width,gfx::SurfaceFormat::A8);wr::ImageDescriptorcbcrDescriptor(desc.cbCrSize(),desc.cbCrSize().width,gfx::SurfaceFormat::A8);aAPI->AddExternalImage(aImageKeys[0],yDescriptor,aExtID,WrExternalImageBufferType::ExternalBuffer,0);aAPI->AddExternalImage(aImageKeys[1],cbcrDescriptor,aExtID,WrExternalImageBufferType::ExternalBuffer,1);aAPI->AddExternalImage(aImageKeys[2],cbcrDescriptor,aExtID,WrExternalImageBufferType::ExternalBuffer,2);}}voidBufferTextureHost::PushExternalImage(wr::DisplayListBuilder&aBuilder,constWrRect&aBounds,constWrRect&aClip,wr::ImageRenderingaFilter,Range<constwr::ImageKey>&aImageKeys){if(GetFormat()!=gfx::SurfaceFormat::YUV){MOZ_ASSERT(aImageKeys.length()==1);aBuilder.PushImage(aBounds,aClip,aFilter,aImageKeys[0]);}else{MOZ_ASSERT(aImageKeys.length()==3);aBuilder.PushYCbCrPlanarImage(aBounds,aClip,aImageKeys[0],aImageKeys[1],aImageKeys[2],WrYuvColorSpace::Rec601,aFilter);}}voidTextureHost::DeserializeReadLock(constReadLockDescriptor&aDesc,ISurfaceAllocator*aAllocator){RefPtr<TextureReadLock>lock=TextureReadLock::Deserialize(aDesc,aAllocator);if(!lock){return;}// If mReadLock is not null it means we haven't unlocked it yet and the content// side should not have been able to write into this texture and send a new lock!MOZ_ASSERT(!mReadLock);mReadLock=lock.forget();}voidTextureHost::SetReadLock(TextureReadLock*aReadLock){if(!aReadLock){return;}// If mReadLock is not null it means we haven't unlocked it yet and the content// side should not have been able to write into this texture and send a new lock!MOZ_ASSERT(!mReadLock);mReadLock=aReadLock;}voidTextureHost::ReadUnlock(){if(mReadLock){mReadLock->ReadUnlock();mReadLock=nullptr;}}boolBufferTextureHost::EnsureWrappingTextureSource(){MOZ_ASSERT(!mHasIntermediateBuffer);if(mFirstSource&&mFirstSource->IsOwnedBy(this)){returntrue;}// We don't own it, apparently.if(mFirstSource){mNeedsFullUpdate=true;mFirstSource=nullptr;}if(!mProvider){returnfalse;}if(mFormat==gfx::SurfaceFormat::YUV){mFirstSource=mProvider->CreateDataTextureSourceAroundYCbCr(this);}else{RefPtr<gfx::DataSourceSurface>surf=gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),ImageDataSerializer::ComputeRGBStride(mFormat,mSize.width),mSize,mFormat);if(!surf){returnfalse;}mFirstSource=mProvider->CreateDataTextureSourceAround(surf);}if(!mFirstSource){// BasicCompositor::CreateDataTextureSourceAround never returns null// and we don't expect to take this branch if we are using another backend.// Returning false is fine but if we get into this situation it probably// means something fishy is going on, like a texture being used with// several compositor backends.NS_WARNING("Failed to use a BufferTextureHost without intermediate buffer");returnfalse;}mFirstSource->SetUpdateSerial(mUpdateSerial);mFirstSource->SetOwner(this);returntrue;}staticboolIsCompatibleTextureSource(TextureSource*aTexture,constBufferDescriptor&aDescriptor,TextureSourceProvider*aProvider){if(!aProvider){returnfalse;}switch(aDescriptor.type()){caseBufferDescriptor::TYCbCrDescriptor:{constYCbCrDescriptor&ycbcr=aDescriptor.get_YCbCrDescriptor();if(!aProvider->SupportsEffect(EffectTypes::YCBCR)){returnaTexture->GetFormat()==gfx::SurfaceFormat::B8G8R8X8&&aTexture->GetSize()==ycbcr.ySize();}if(aTexture->GetFormat()!=gfx::SurfaceFormat::A8||aTexture->GetSize()!=ycbcr.ySize()){returnfalse;}autocbTexture=aTexture->GetSubSource(1);if(!cbTexture||cbTexture->GetFormat()!=gfx::SurfaceFormat::A8||cbTexture->GetSize()!=ycbcr.cbCrSize()){returnfalse;}autocrTexture=aTexture->GetSubSource(2);if(!crTexture||crTexture->GetFormat()!=gfx::SurfaceFormat::A8||crTexture->GetSize()!=ycbcr.cbCrSize()){returnfalse;}returntrue;}caseBufferDescriptor::TRGBDescriptor:{constRGBDescriptor&rgb=aDescriptor.get_RGBDescriptor();returnaTexture->GetFormat()==rgb.format()&&aTexture->GetSize()==rgb.size();}default:{returnfalse;}}}voidBufferTextureHost::PrepareTextureSource(CompositableTextureSourceRef&aTexture){// Reuse WrappingTextureSourceYCbCrBasic to reduce memory consumption.if(mFormat==gfx::SurfaceFormat::YUV&&!mHasIntermediateBuffer&&aTexture.get()&&aTexture->AsWrappingTextureSourceYCbCrBasic()&&aTexture->NumCompositableRefs()<=1&&aTexture->GetSize()==GetSize()){aTexture->AsSourceBasic()->SetBufferTextureHost(this);aTexture->AsDataTextureSource()->SetOwner(this);mFirstSource=aTexture->AsDataTextureSource();mNeedsFullUpdate=true;}if(!mHasIntermediateBuffer){EnsureWrappingTextureSource();}if(mFirstSource&&mFirstSource->IsOwnedBy(this)){// We are already attached to a TextureSource, nothing to do except tell// the compositable to use it.aTexture=mFirstSource.get();return;}// We don't own it, apparently.if(mFirstSource){mNeedsFullUpdate=true;mFirstSource=nullptr;}DataTextureSource*texture=aTexture.get()?aTexture->AsDataTextureSource():nullptr;boolcompatibleFormats=texture&&IsCompatibleTextureSource(texture,mDescriptor,mProvider);boolshouldCreateTexture=!compatibleFormats||texture->NumCompositableRefs()>1||texture->HasOwner();if(!shouldCreateTexture){mFirstSource=texture;mFirstSource->SetOwner(this);mNeedsFullUpdate=true;// It's possible that texture belonged to a different compositor,// so make sure we update it (and all of its siblings) to the// current one.RefPtr<TextureSource>it=mFirstSource;while(it){it->SetTextureSourceProvider(mProvider);it=it->GetNextSibling();}}}boolBufferTextureHost::BindTextureSource(CompositableTextureSourceRef&aTexture){MOZ_ASSERT(mLocked);MOZ_ASSERT(mFirstSource);aTexture=mFirstSource;return!!aTexture;}boolBufferTextureHost::AcquireTextureSource(CompositableTextureSourceRef&aTexture){if(!UploadIfNeeded()){returnfalse;}aTexture=mFirstSource;return!!mFirstSource;}voidBufferTextureHost::UnbindTextureSource(){if(mFirstSource&&mFirstSource->IsOwnedBy(this)){mFirstSource->Unbind();}// This texture is not used by any layer anymore.// If the texture doesn't have an intermediate buffer, it means we are// compositing synchronously on the CPU, so we don't need to wait until// the end of the next composition to ReadUnlock (which other textures do// by default).// If the texture has an intermediate buffer we don't care either because// texture uploads are also performed synchronously for BufferTextureHost.ReadUnlock();}gfx::SurfaceFormatBufferTextureHost::GetFormat()const{// mFormat is the format of the data that we share with the content process.// GetFormat, on the other hand, expects the format that we present to the// Compositor (it is used to choose the effect type).// if the compositor does not support YCbCr effects, we give it a RGBX texture// instead (see BufferTextureHost::Upload)if(mFormat==gfx::SurfaceFormat::YUV&&mProvider&&!mProvider->SupportsEffect(EffectTypes::YCBCR)){returngfx::SurfaceFormat::R8G8B8X8;}returnmFormat;}YUVColorSpaceBufferTextureHost::GetYUVColorSpace()const{if(mFormat==gfx::SurfaceFormat::YUV){constYCbCrDescriptor&desc=mDescriptor.get_YCbCrDescriptor();returndesc.yUVColorSpace();}returnYUVColorSpace::UNKNOWN;}boolBufferTextureHost::UploadIfNeeded(){returnMaybeUpload(!mNeedsFullUpdate?&mMaybeUpdatedRegion:nullptr);}boolBufferTextureHost::MaybeUpload(nsIntRegion*aRegion){autoserial=mFirstSource?mFirstSource->GetUpdateSerial():0;if(serial==mUpdateSerial){returntrue;}if(serial==0){// 0 means the source has no valid contentaRegion=nullptr;}if(!Upload(aRegion)){returnfalse;}if(mHasIntermediateBuffer){// We just did the texture upload, the content side can now freely write// into the shared buffer.ReadUnlock();}// We no longer have an invalid region.mNeedsFullUpdate=false;mMaybeUpdatedRegion.SetEmpty();// If upload returns true we know mFirstSource is not nullmFirstSource->SetUpdateSerial(mUpdateSerial);returntrue;}boolBufferTextureHost::Upload(nsIntRegion*aRegion){uint8_t*buf=GetBuffer();if(!buf){// We don't have a buffer; a possible cause is that the IPDL actor// is already dead. This inevitably happens as IPDL actors can die// at any time, so we want to silently return in this case.// another possible cause is that IPDL failed to map the shmem when// deserializing it.returnfalse;}if(!mProvider){// This can happen if we send textures to a compositable that isn't yet// attached to a layer.returnfalse;}if(!mHasIntermediateBuffer&&EnsureWrappingTextureSource()){returntrue;}if(mFormat==gfx::SurfaceFormat::UNKNOWN){NS_WARNING("BufferTextureHost: unsupported format!");returnfalse;}elseif(mFormat==gfx::SurfaceFormat::YUV){constYCbCrDescriptor&desc=mDescriptor.get_YCbCrDescriptor();if(!mProvider->SupportsEffect(EffectTypes::YCBCR)){RefPtr<gfx::DataSourceSurface>surf=ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf,mDescriptor.get_YCbCrDescriptor());if(NS_WARN_IF(!surf)){returnfalse;}if(!mFirstSource){mFirstSource=mProvider->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR);mFirstSource->SetOwner(this);}mFirstSource->Update(surf,aRegion);returntrue;}RefPtr<DataTextureSource>srcY;RefPtr<DataTextureSource>srcU;RefPtr<DataTextureSource>srcV;if(!mFirstSource){// We don't support BigImages for YCbCr compositing.srcY=mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);srcU=mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);srcV=mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);mFirstSource=srcY;mFirstSource->SetOwner(this);srcY->SetNextSibling(srcU);srcU->SetNextSibling(srcV);}else{// mFormat never changes so if this was created as a YCbCr host and already// contains a source it should already have 3 sources.// BufferTextureHost only uses DataTextureSources so it is safe to assume// all 3 sources are DataTextureSource.MOZ_ASSERT(mFirstSource->GetNextSibling());MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());srcY=mFirstSource;srcU=mFirstSource->GetNextSibling()->AsDataTextureSource();srcV=mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource();}RefPtr<gfx::DataSourceSurface>tempY=gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf,desc),desc.ySize().width,desc.ySize(),gfx::SurfaceFormat::A8);RefPtr<gfx::DataSourceSurface>tempCb=gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf,desc),desc.cbCrSize().width,desc.cbCrSize(),gfx::SurfaceFormat::A8);RefPtr<gfx::DataSourceSurface>tempCr=gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf,desc),desc.cbCrSize().width,desc.cbCrSize(),gfx::SurfaceFormat::A8);// We don't support partial updates for Y U V texturesNS_ASSERTION(!aRegion,"Unsupported partial updates for YCbCr textures");if(!tempY||!tempCb||!tempCr||!srcY->Update(tempY)||!srcU->Update(tempCb)||!srcV->Update(tempCr)){NS_WARNING("failed to update the DataTextureSource");returnfalse;}}else{// non-YCbCr casensIntRegion*regionToUpdate=aRegion;if(!mFirstSource){mFirstSource=mProvider->CreateDataTextureSource(mFlags);mFirstSource->SetOwner(this);if(mFlags&TextureFlags::COMPONENT_ALPHA){// Update the full region the first time for component alpha textures.regionToUpdate=nullptr;}}RefPtr<gfx::DataSourceSurface>surf=gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),ImageDataSerializer::ComputeRGBStride(mFormat,mSize.width),mSize,mFormat);if(!surf){returnfalse;}if(!mFirstSource->Update(surf.get(),regionToUpdate)){NS_WARNING("failed to update the DataTextureSource");returnfalse;}}MOZ_ASSERT(mFirstSource);returntrue;}already_AddRefed<gfx::DataSourceSurface>BufferTextureHost::GetAsSurface(){RefPtr<gfx::DataSourceSurface>result;if(mFormat==gfx::SurfaceFormat::UNKNOWN){NS_WARNING("BufferTextureHost: unsupported format!");returnnullptr;}elseif(mFormat==gfx::SurfaceFormat::YUV){result=ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(GetBuffer(),mDescriptor.get_YCbCrDescriptor());if(NS_WARN_IF(!result)){returnnullptr;}}else{result=gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),mSize,mFormat);}returnresult.forget();}ShmemTextureHost::ShmemTextureHost(constipc::Shmem&aShmem,constBufferDescriptor&aDesc,ISurfaceAllocator*aDeallocator,TextureFlagsaFlags):BufferTextureHost(aDesc,aFlags),mDeallocator(aDeallocator){if(aShmem.IsReadable()){mShmem=MakeUnique<ipc::Shmem>(aShmem);}else{// This can happen if we failed to map the shmem on this process, perhaps// because it was big and we didn't have enough contiguous address space// available, even though we did on the child process.// As a result this texture will be in an invalid state and Lock will// always fail.gfxCriticalNote<<"Failed to create a valid ShmemTextureHost";}MOZ_COUNT_CTOR(ShmemTextureHost);}ShmemTextureHost::~ShmemTextureHost(){MOZ_ASSERT(!mShmem||(mFlags&TextureFlags::DEALLOCATE_CLIENT),"Leaking our buffer");DeallocateDeviceData();MOZ_COUNT_DTOR(ShmemTextureHost);}voidShmemTextureHost::DeallocateSharedData(){if(mShmem){MOZ_ASSERT(mDeallocator,"Shared memory would leak without a ISurfaceAllocator");mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem);mShmem=nullptr;}}voidShmemTextureHost::ForgetSharedData(){if(mShmem){mShmem=nullptr;}}voidShmemTextureHost::OnShutdown(){mShmem=nullptr;}uint8_t*ShmemTextureHost::GetBuffer(){returnmShmem?mShmem->get<uint8_t>():nullptr;}size_tShmemTextureHost::GetBufferSize(){returnmShmem?mShmem->Size<uint8_t>():0;}MemoryTextureHost::MemoryTextureHost(uint8_t*aBuffer,constBufferDescriptor&aDesc,TextureFlagsaFlags):BufferTextureHost(aDesc,aFlags),mBuffer(aBuffer){MOZ_COUNT_CTOR(MemoryTextureHost);}MemoryTextureHost::~MemoryTextureHost(){MOZ_ASSERT(!mBuffer||(mFlags&TextureFlags::DEALLOCATE_CLIENT),"Leaking our buffer");DeallocateDeviceData();MOZ_COUNT_DTOR(MemoryTextureHost);}voidMemoryTextureHost::DeallocateSharedData(){if(mBuffer){GfxMemoryImageReporter::WillFree(mBuffer);}delete[]mBuffer;mBuffer=nullptr;}voidMemoryTextureHost::ForgetSharedData(){mBuffer=nullptr;}uint8_t*MemoryTextureHost::GetBuffer(){returnmBuffer;}size_tMemoryTextureHost::GetBufferSize(){// MemoryTextureHost just trusts that the buffer size is large enough to read// anything we need to. That's because MemoryTextureHost has to trust the buffer// pointer anyway, so the security model here is just that MemoryTexture's// are restricted to same-process clients.returnstd::numeric_limits<size_t>::max();}TextureParent::TextureParent(HostIPCAllocator*aSurfaceAllocator,uint64_taSerial,constwr::MaybeExternalImageId&aExternalImageId):mSurfaceAllocator(aSurfaceAllocator),mSerial(aSerial),mExternalImageId(aExternalImageId){MOZ_COUNT_CTOR(TextureParent);}TextureParent::~TextureParent(){MOZ_COUNT_DTOR(TextureParent);}voidTextureParent::NotifyNotUsed(uint64_taTransactionId){if(!mTextureHost){return;}mSurfaceAllocator->NotifyNotUsed(this,aTransactionId);}boolTextureParent::Init(constSurfaceDescriptor&aSharedData,constLayersBackend&aBackend,constTextureFlags&aFlags){mTextureHost=TextureHost::Create(aSharedData,mSurfaceAllocator,aBackend,aFlags,mExternalImageId);if(mTextureHost){mTextureHost->mActor=this;}return!!mTextureHost;}voidTextureParent::Destroy(){if(!mTextureHost){return;}// ReadUnlock here to make sure the ReadLock's shmem does not outlive the// protocol that created it.mTextureHost->ReadUnlock();if(mTextureHost->GetFlags()&TextureFlags::DEALLOCATE_CLIENT){mTextureHost->ForgetSharedData();}mTextureHost->mActor=nullptr;mTextureHost=nullptr;}voidTextureHost::ReceivedDestroy(PTextureParent*aActor){static_cast<TextureParent*>(aActor)->RecvDestroy();}mozilla::ipc::IPCResultTextureParent::RecvRecycleTexture(constTextureFlags&aTextureFlags){if(!mTextureHost){returnIPC_OK();}mTextureHost->RecycleTexture(aTextureFlags);returnIPC_OK();}////////////////////////////////////////////////////////////////////////////////}// namespace layers}// namespace mozilla